package services

import (
	"errors"
	"sort"
	"time"
	"yuanaiproblem/dao"
	"yuanaiproblem/models/dto"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// GetUserList 获取用户列表
// 入参：用户名（可选）、角色（可选）、页码、页大小
// 流程：调用DAO层查询用户列表 -> 转换为响应格式 -> 返回结果
func GetUserList(username, role string, page, pageSize int) (*dto.UserListResult, error) {
	// 调用DAO层查询符合条件的用户（带分页）
	users, total, err := dao.GetUsers(username, role, page, pageSize)
	if err != nil {
		return nil, err // 传递底层查询错误
	}

	// 转换DAO查询结果为响应DTO
	userResponses := make([]dto.UserListResponse, 0, len(users))
	for _, user := range users {
		userResponses = append(userResponses, dto.UserListResponse{
			ID:        uint(user.ID),
			Username:  user.Username,
			Role:      user.Role,
			CreatedAt: user.CreatedAt,
			UpdatedAt: user.UpdatedAt,
		})
	}

	// 包装总记录数和用户列表并返回
	return &dto.UserListResult{
		Total: total,
		Users: userResponses,
	}, nil
}

// UpdateUser 处理更新用户
// 入参：当前用户ID、目标用户ID、当前用户是否为管理员、待更新的用户名/密码/角色（可选指针）
// 流程：验证目标用户存在性 -> 按字段处理更新逻辑（含权限校验） -> 执行更新 -> 返回更新后用户信息
func UpdateUser(
	currentUserID int32,
	targetUserID int32,
	isAdmin bool,
	username *string,
	password *string,
	role *string,
) (*dto.UpdateUserResponse, error) {
	// 验证目标用户是否存在
	user, err := dao.GetUserByID(targetUserID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, err // 其他查询错误直接返回
	}

	// 用于存储待更新的字段
	updates := make(map[string]interface{})

	// 处理用户名更新
	if username != nil {
		// 检查新用户名是否已被其他用户使用
		exists, err := dao.CheckUsernameExists(*username, targetUserID)
		if err != nil {
			return nil, err // 传递查询错误
		}
		if exists {
			return nil, errors.New("用户名已存在") // 用户名冲突错误
		}
		updates["username"] = *username // 加入更新字段
	}

	// 处理密码更新
	if password != nil {
		// 权限校验：允许管理员或用户本人更新密码
		if !(isAdmin || currentUserID == targetUserID) {
			return nil, errors.New("无权限更新该用户密码")
		}
		// 加密密码
		hashedPassword, err := bcrypt.GenerateFromPassword(
			[]byte(*password),
			bcrypt.DefaultCost, // 使用默认加密强度
		)
		if err != nil {
			return nil, errors.New("密码处理失败: " + err.Error())
		}
		updates["password_hash"] = string(hashedPassword) // 存储加密后的密码
	}

	// 处理角色更新
	if role != nil {
		// 权限校验：仅管理员可更新角色
		if !isAdmin {
			return nil, errors.New("仅管理员可更新角色")
		}
		// 验证角色合法性
		validRoles := map[string]bool{"user": true, "admin": true}
		if !validRoles[*role] {
			return nil, errors.New("无效的角色")
		}
		updates["role"] = *role // 加入更新字段
	}

	// 执行更新（若有字段需要更新）
	if len(updates) > 0 {
		updates["updated_at"] = time.Now() // 强制更新时间戳
		// 调用DAO执行更新
		if err := dao.UpdateUser(user, updates); err != nil {
			return nil, err
		}
		// 重新查询更新后的用户信息
		user, err = dao.GetUserByID(targetUserID)
		if err != nil {
			return nil, err
		}
	}

	// 转换为响应格式并返回
	return &dto.UpdateUserResponse{
		ID:        uint(user.ID),
		Username:  user.Username,
		Role:      user.Role,
		CreatedAt: user.CreatedAt,
		UpdatedAt: user.UpdatedAt,
	}, nil
}

// GetUserRecords 查询用户的出题和组卷记录
// 入参：用户ID、记录类型、页码、页大小
// 返回：记录列表、总条数、错误
func GetUserRecords(userID int32, recordType string, page, pageSize int) ([]dto.UserRecordResponse, int64, error) {
	// 根据记录类型查询不同的记录
	switch recordType {
	case "question":
		// 查询个人出题记录
		return getQuestionRecords(userID, page, pageSize)
	case "paper":
		// 查询个人组卷记录
		return getPaperRecords(userID, page, pageSize)
	default:
		// 查询全部记录-合并出题和组卷记录，按创建时间排序
		return getAllRecords(userID, page, pageSize)
	}
}

// 查询个人出题记录
func getQuestionRecords(userID int32, page, pageSize int) ([]dto.UserRecordResponse, int64, error) {
	// 调用DAO层查询出题记录（分页）
	questions, total, err := dao.GetUserAllQuestions(userID, page, pageSize)
	if err != nil {
		return nil, 0, err
	}

	// 转换为统一的记录DTO
	records := make([]dto.UserRecordResponse, 0, len(questions))
	for _, q := range questions {
		records = append(records, dto.UserRecordResponse{
			Type:      "question", // 记录类型：出题
			Title:     q.Title,    // 题目标题
			CreatedAt: q.CreatedAt,
		})
	}
	return records, total, nil
}

// 查询个人组卷记录
func getPaperRecords(userID int32, page, pageSize int) ([]dto.UserRecordResponse, int64, error) {
	// 调用DAO层查询组卷记录（分页）
	papers, total, err := dao.GetUserAllPapers(userID, page, pageSize)
	if err != nil {
		return nil, 0, err
	}

	// 转换为统一的记录DTO
	records := make([]dto.UserRecordResponse, 0, len(papers))
	for _, p := range papers {
		records = append(records, dto.UserRecordResponse{
			ID:        p.ID,
			Type:      "paper", // 记录类型：组卷
			Title:     p.Title, // 试卷标题
			CreatedAt: p.CreatedAt,
		})
	}
	return records, total, nil
}

// 合并查询全部记录（按创建时间倒序）
func getAllRecords(userID int32, page, pageSize int) ([]dto.UserRecordResponse, int64, error) {
	// 分别查询出题和组卷记录（此处简化处理，实际可通过数据库联表优化）
	questionRecords, qTotal, err := getQuestionRecords(userID, 1, pageSize*2) // 多查一些用于合并排序
	if err != nil {
		return nil, 0, err
	}
	paperRecords, pTotal, err := getPaperRecords(userID, 1, pageSize*2)
	if err != nil {
		return nil, 0, err
	}

	// 合并记录并按创建时间倒序排序
	allRecords := append(questionRecords, paperRecords...)
	sort.Slice(allRecords, func(i, j int) bool {
		return allRecords[i].CreatedAt.After(allRecords[j].CreatedAt)
	})

	// 手动分页（实际应通过数据库排序分页，此处为简化示例）
	start := (page - 1) * pageSize
	end := start + pageSize
	if start >= len(allRecords) {
		return []dto.UserRecordResponse{}, qTotal + pTotal, nil
	}
	if end > len(allRecords) {
		end = len(allRecords)
	}

	return allRecords[start:end], qTotal + pTotal, nil
}
